using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using FreeLancer.HRB.Services;
using FreeLancer.HRB.Domains;

namespace FreeLancer.HRB.Core
{
  /// <summary>
  /// A page is much like a post, but is not part of the
  /// blog chronology and is more static in nature.
  /// <remarks>
  /// Pages can be used for "About" pages or other static
  /// information.
  /// </remarks>
  /// </summary>
  public sealed class Page : IPublishable
  {
    #region Properties

    private FreeLancer.HRB.Domains.Page _data;
    /// <summary>
    /// Data of Page.
    /// </summary>
    public FreeLancer.HRB.Domains.Page Data
    {
      get { return _data; }
      set { _data = value; }
    }

    /// <summary>
    /// Gets or sets the Slug of the Page.
    /// A Slug is the relative URL used by the pages.
    /// </summary>
    public string Slug
    {
      get
      {
        if (string.IsNullOrEmpty(_data.Slug))
          return Utils.RemoveIllegalCharacters(Title);

        return _data.Slug;
      }
    }

    private static object _syncRoot = new object();
    private static List<Page> _pages;
    /// <summary>
    /// A sorted collection of all posts in the blog.
    /// Sorted by date.
    /// </summary>
    public static List<Page> Pages
    {
      get
      {
        if (_pages == null)
        {
          lock (_syncRoot)
          {
            if (_pages == null)
            {
              _pages = FillPages();
              _pages.TrimExcess();
              _pages.Sort(delegate(Page p1, Page p2) 
              { return String.Compare(p1.Title, p2.Title); });
            }
          }
        }

        return _pages;
      }
    }

    private Guid _page;

    /// <summary>
    /// Parent page
    /// </summary>
    public Guid Parent
    {
      get { return _page; }
      set { _page = value; }
    }

    #endregion

    #region Constructor

    /// <summary>
    /// Construtor
    /// </summary>
    /// <param name="data">Page data</param>
    public Page(FreeLancer.HRB.Domains.Page data)
    {
      if (data == null)
        throw new ArgumentNullException();

      _data = data;
      Initialize();
    }

    private void Initialize()
    {
      PageService service = GlobalCache.PageServiceInstance;
      FreeLancer.HRB.Domains.Page pageDomains = service.GetByPageIdLanguageId(_data.PageId, _data.LanguageId);

      if (_page != null)
        _page = pageDomains.PageId;
    }

    #endregion

    #region IPublishable Members

    /// <summary>
    /// Gets the Title or the object.
    /// </summary>
    public string Title
    {
      get { return _data.Title; }
    }

    /// <summary>
    /// Gets the Content or the object.
    /// </summary>
    public string Content
    {
      get { return _data.PageContent; }
    }

    /// <summary>
    /// Gets when the Page was created.
    /// </summary>
    public DateTime DateCreated
    {
      get { return _data.DateCreated.Value; }
    }

    /// <summary>
    /// Gets when the Page was modified.
    /// </summary>
    public DateTime DateModified
    {
      get { return _data.DateModified.Value; }
    }

    /// <summary>
    /// Id of the Page
    /// </summary>
    public Guid Id
    {
      get { return _data.PageId; }
    }

    /// <summary>
    /// A relative-to-the-site-root path to the post.
    /// Only for in-site use.
    /// </summary>
    public string RelativeLink
    {
      get
      {
        string slug = Utils.RemoveIllegalCharacters(Slug) + WebAppSettings.Instance.FileExtension;
        return Utils.RelativeWebRoot + "page/" + slug;
      }
    }

    /// <summary>
    /// The absolute link to the post.
    /// </summary>
    public Uri AbsoluteLink
    {
      get { return Utils.ConvertToAbsolute(RelativeLink); }
    }

    /// <summary>
    /// Gets the Description or the object.
    /// </summary>
    public string Description
    {
      get { return _data.Description; }
    }

    /// <summary>
    /// Not available. This will return empty string.
    /// </summary>
    public string Author
    {
      get { return string.Empty; }
    }

    /// <summary>
    /// Raises the Serving event
    /// </summary>
    public void OnServing(ServingEventArgs eventArgs)
    {
      if (Serving != null)
      {
        Serving(this, eventArgs);
      }
    }

    /// <summary>
    /// Not available.
    /// </summary>
    public List<Category> Categories
    {
      get { return null; }
    }

    /// <summary>
    /// Gets or sets whether or not this page should be published.
    /// </summary>
    public bool IsPublished
    {
      get { return _data.IsPublished; }
    }

    /// <summary>
    /// Gets a value indicating whether the current user is authenticated.
    /// </summary>
    /// <value>
    /// 	<c>true</c> if this instance is authenticated; otherwise, <c>false</c>.
    /// </value>
    public bool IsVisible 
    {
      get { return Thread.CurrentPrincipal.Identity.IsAuthenticated && _data.IsPublished; }
    }

    #endregion

    #region Events

    /// <summary>
    /// Occurs when the page is being served to the output stream.
    /// </summary>
    public static event EventHandler<ServingEventArgs> Serving;
    /// <summary>
    /// Raises the event in a safe way
    /// </summary>
    public static void OnServing(Page page, ServingEventArgs arg)
    {
      if (Serving != null)
      {
        Serving(page, arg);
      }
    }

    #endregion

    #region Helpers

    private static List<Page> FillPages()
    {
      List<Page> pages = new List<Page>();
      PageService service = GlobalCache.PageServiceInstance;

      TList<FreeLancer.HRB.Domains.Page> pageDomains = service.GetAll();
      foreach (FreeLancer.HRB.Domains.Page pageDomain in pageDomains)
      {
        pages.Add(new Page(pageDomain));
      }

      return pages;
    }

    #endregion

    #region Static methods

    /// <summary>
    /// Get Page by Id
    /// </summary>
    /// <param name="id">Page id</param>
    /// <returns>Page</returns>
    public static Page GetPage(Guid id)
    {
      return Pages.Find(delegate(Page p)
            {
              if (p.Id == id)
                return true;
              return false;
            });
    }

    /// <summary>
    /// Hard code to null. Not support in this version.
    /// </summary>
    public static Page GetFrontPage()
    {
      return null;
    }

    #endregion
  }
}
